package org.dreamwork.jasmine2.web.controls;

import org.dreamwork.util.NameValueCollection;
import org.dreamwork.util.ResourceManager;
import org.dreamwork.jasmine2.events.EventException;
import org.dreamwork.jasmine2.engine.IPostbackHandler;
import org.dreamwork.jasmine2.engine.HttpContext;
import org.dreamwork.jasmine2.web.IWebControl;
import org.dreamwork.jasmine2.web.html.GenericHtmlControl;

import java.util.List;
import java.util.ArrayList;
import java.io.IOException;

/**
 * Created by IntelliJ IDEA.
 * User: seth
 * Date: 2009-10-19
 * Time: 15:16:23
 */
public class Pagging2 extends Panel implements IPostbackHandler {
    private int totalRows;
    private int totalPages;
    private int pageSize = 10;
    private int pageNo = 1;
    private int max = 10;

    private boolean useDefaultCss = true;
    private boolean showGoto = false;

    private Panel left, right;
    private GenericHtmlControl ul;
    private TextBox pageNoBox;
    private Button button;
    private String handler;

    public Pagging2 () {
        viewStateEnabled = false;
        autoPostback = true;
    }

    public String getHandler () {
        return handler;
    }

    public void setHandler (String handler) {
        this.handler = handler;
    }

    public int getTotalRows () {
        return totalRows;
    }

    public void setTotalRows (int totalRows) {
        this.totalRows = totalRows;
    }

    public int getPageSize () {
        return pageSize;
    }

    public void setPageSize (int pageSize) {
        this.pageSize = pageSize;
    }

    public int getPageNo () {
        return pageNo;
    }

    public void setPageNo (int pageNo) {
        this.pageNo = pageNo < 1 ? 1 : pageNo;
    }

    public int getMax () {
        return max;
    }

    public void setMax (int max) {
        this.max = max < 10 ? 10 : max;
    }

    public boolean isUseDefaultCss () {
        return useDefaultCss;
    }

    public void setUseDefaultCss (boolean useDefaultCss) {
        this.useDefaultCss = useDefaultCss;
    }

    public boolean isShowGoto () {
        return showGoto;
    }

    public void setShowGoto (boolean showGoto) {
        this.showGoto = showGoto;
    }

    @Override
    public void init () {
        super.init ();
        if (autoPostback)
            page.registerClientScriptBlock (InternalJS.class, InternalJS.PAGGING_JS);
        if (useDefaultCss)
            page.registerStyleFile (InternalJS.class, InternalJS.PAGGING_DEFAULT_CSS);
        if (viewStateEnabled)
            stateManager.put ("totalRows", totalRows);        
    }

    public void postbackData (NameValueCollection props) {
        if (!autoPostback) return;
        String pageNoId = id + ".pageNo";
        String pageSizeId = id + ".pageSize";
        String s_page_no = props.getValue (pageNoId);
        String s_page_size = props.getValue (pageSizeId);

        try {
            pageNo = Integer.parseInt (s_page_no);
        } catch (Exception ex) {
            //
        }

        try {
            pageSize = Integer.parseInt (s_page_size);
        } catch (Exception ex) {
            //
        }

        if (viewStateEnabled)
            stateManager.put ("totalRows", totalRows);
    }

    @Override
    public void onDataBind (Object sender) throws EventException {
        String expression = getDynamicAttribute ("totalRows");
        if (expression != null) {
            try {
                Object value = page.eval (expression);
                if (value != null) {
                    totalRows = ((Number) value).intValue ();
                    if (viewStateEnabled)
                        stateManager.put ("totalRows", totalRows);                    
                }
            } catch (Exception e) {
                e.printStackTrace ();
            }
        }
    }

    @Override
    public void createChildControls () {
        ResourceManager res = ResourceManager.instance ("org.dreamwork.jasmine2.web.controls.Pagging", context.getRequest ().getLocale ());
        left = new Panel ();
        StringBuilder builder = new StringBuilder (res.getStringPattern ("pagging.total-rows", totalRows));
        builder.append (" ").append (res.getStringPattern ("pagging.page-size", pageSize));
        left.addControl (new Literal (builder));
        addControl (left);

        right = new Panel ();

        String handler = autoPostback ? "__jump" : this.handler;

        ul = new GenericHtmlControl ("ul");
        List<PaggingInfo> labels = getPaggingInfos ();
        for (PaggingInfo info : labels) {
            builder = new StringBuilder ("<li><a href=\"javascript:");
            if (info.pageNo == pageNo)
                builder.append ("void(null);\" class=\"pagging-current\"");
            else if (info.pageNo == -1)
                builder.append ("void(null);\" class=\"pagging-dot\"");
            else
                builder.append (handler).append ("('").append (id).append ("', '").append (info.pageNo).append ("')\"");
            builder.append (">").append (info.label).append ("</a></li>\r\n");
            ul.addControl (new Literal (builder.toString ()));
        }
        right.addControl (ul);

        addControl (right);
        Panel clear = new Panel ();
        clear.setAttribute ("class", "default-padding-clear");
        addControl (clear);

        String pageNoId = id + ".pageNo";
        String pageSizeId = id + ".pageSize";

        pageNoBox = new TextBox ();
        pageNoBox.setId (pageNoId);
        pageNoBox.setText (String.valueOf (pageNo));
        right.addControl (pageNoBox);

        Hidden pageSizeBox = new Hidden ();
        pageSizeBox.setId (pageSizeId);
        pageSizeBox.setText (String.valueOf (pageSize));
        right.addControl (pageSizeBox);

        if (showGoto) {
            button = new Button ();
            button.setText (res.getString ("pagging.go"));
            button.setAttribute ("onclick", handler + "('" + id + "')");
            right.addControl (button);
        }
    }

    @Override
    public void onPrerender (IWebControl sender, HttpContext context) throws EventException {
        if (useDefaultCss) {
            ul.setAttribute ("class", "default-pagging-class");
            left.setAttribute ("class", "default-pagging-left");
            right.setAttribute ("class", "default-pagging-right");
        }

        if (showGoto) {
            button.setVisible (true);
            pageNoBox.setAttribute ("type", "text");
            String length = String.valueOf (String.valueOf (totalPages).length ());
            pageNoBox.setAttribute ("size", length);
            pageNoBox.setAttribute ("maxlength", length);
        } else {
            pageNoBox.setAttribute ("type", "hidden");
        }
    }

    @Override
    protected void loadViewState (Object savedState) throws IOException {
        stateManager.loadViewState (savedState);
        Integer I = (Integer) stateManager.get ("totalRows");
        if (I != null)
            totalRows = I;
    }

    private void calculateTotalPages () {
        if (pageSize <= 0) pageSize = 10;
        if (pageNo <= 0) pageNo = 1;
        totalPages = totalRows / pageSize;
        if (totalRows % pageSize != 0) totalPages++;
        if (totalPages == 0) totalPages++;
        if (pageNo > totalPages) pageNo = totalPages;
    }

    private List<PaggingInfo> getPaggingInfos () {
        calculateTotalPages ();
        List<PaggingInfo> labels = new ArrayList<PaggingInfo> ();

        if (totalPages <= max) for (int i = 1; i <= totalPages; i ++) {
            labels.add (new PaggingInfo (String.valueOf (i), i));
        } else {
            labels.add (new PaggingInfo ("1", 1));

            if (pageNo <= max /2) {
                int i;
                for (i = 2; i <= max - 2; i ++)
                    labels.add (new PaggingInfo (String.valueOf (i), i));
                if (i < totalPages - 1)
                    labels.add (new PaggingInfo ("...", -1));
            } else if ((totalPages - pageNo) <= max / 2) {
                int start = totalPages - max + 3;
                if (start > 2)
                    labels.add (new PaggingInfo ("...", -1));
                if (start <= 2) start = 2;
                for (int i = start; i < totalPages; i ++) {
                    labels.add (new PaggingInfo (String.valueOf (i), i));
                }
            } else {
                labels.add (new PaggingInfo ("...", -1));
                int start = pageNo - (max - 4) / 2;
                int end = pageNo + (max - 4) / 2;
                for (int i = start; i < end; i ++)
                    labels.add (new PaggingInfo (String.valueOf (i), i));
                labels.add (new PaggingInfo ("...", -1));
            }

            labels.add (new PaggingInfo (String.valueOf (totalPages), totalPages));
        }
        return labels;
    }

    private static class PaggingInfo {
        String label;
        int pageNo;

        private PaggingInfo (String label, int pageNo) {
            this.label = label;
            this.pageNo = pageNo;
        }
    }
}